/**
 * @file       st7735.c
 * @author     mz8023yt
 * @email      mz8023yt@163.com
 * @version    V1.0
 * @date       2022-03-13
 * @brief      st7735 lcd driver
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "st7735.h"
#include <stdint.h>

void st7735_cmd_write(struct st7735* lcd, uint8_t cmd);
void st7735_dat_write(struct st7735* lcd, uint8_t dat);
void st7735_area_set(struct st7735* lcd, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);

void st7735_init(struct st7735* lcd)
{
	lcd->ops.pin.rst(LOW);
	lcd->ops.time.msleep(100);
	lcd->ops.pin.rst(LOW);
	lcd->ops.time.msleep(120);

	st7735_cmd_write(lcd, 0x11);
	lcd->ops.time.msleep(120);

	st7735_cmd_write(lcd, 0x21);

	st7735_cmd_write(lcd, 0xB1);
	st7735_dat_write(lcd, 0x05);
	st7735_dat_write(lcd, 0x3A);
	st7735_dat_write(lcd, 0x3A);

	st7735_cmd_write(lcd, 0xB2);
	st7735_dat_write(lcd, 0x05);
	st7735_dat_write(lcd, 0X3A);
	st7735_dat_write(lcd, 0X3A);

	st7735_cmd_write(lcd, 0xB3);
	st7735_dat_write(lcd, 0x05);
	st7735_dat_write(lcd, 0x3A);
	st7735_dat_write(lcd, 0x3A);
	st7735_dat_write(lcd, 0x05);
	st7735_dat_write(lcd, 0x3A);
	st7735_dat_write(lcd, 0x3A);

	st7735_cmd_write(lcd, 0xB4);
	st7735_dat_write(lcd, 0x03);

	st7735_cmd_write(lcd, 0xC0);
	st7735_dat_write(lcd, 0x62);
	st7735_dat_write(lcd, 0x02);
	st7735_dat_write(lcd, 0x04);

	st7735_cmd_write(lcd, 0xC1);
	st7735_dat_write(lcd, 0xC0);

	st7735_cmd_write(lcd, 0xC2);
	st7735_dat_write(lcd, 0x0D);
	st7735_dat_write(lcd, 0X00);

	st7735_cmd_write(lcd, 0xC3);
	st7735_dat_write(lcd, 0x8D);
	st7735_dat_write(lcd, 0x6A);

	st7735_cmd_write(lcd, 0xC4);
	st7735_dat_write(lcd, 0x8D);
	st7735_dat_write(lcd, 0xEE);

	st7735_cmd_write(lcd, 0xC5);
	st7735_dat_write(lcd, 0x0E);

	st7735_cmd_write(lcd, 0xE0);
	st7735_dat_write(lcd, 0x10);
	st7735_dat_write(lcd, 0x0E);
	st7735_dat_write(lcd, 0x02);
	st7735_dat_write(lcd, 0x03);
	st7735_dat_write(lcd, 0x0E);
	st7735_dat_write(lcd, 0x07);
	st7735_dat_write(lcd, 0x02);
	st7735_dat_write(lcd, 0x07);
	st7735_dat_write(lcd, 0x0A);
	st7735_dat_write(lcd, 0x12);
	st7735_dat_write(lcd, 0x27);
	st7735_dat_write(lcd, 0x37);
	st7735_dat_write(lcd, 0x00);
	st7735_dat_write(lcd, 0x0D);
	st7735_dat_write(lcd, 0x0E);
	st7735_dat_write(lcd, 0x10);

	st7735_cmd_write(lcd, 0xE1);
	st7735_dat_write(lcd, 0x10);
	st7735_dat_write(lcd, 0x0E);
	st7735_dat_write(lcd, 0x03);
	st7735_dat_write(lcd, 0x03);
	st7735_dat_write(lcd, 0x0F);
	st7735_dat_write(lcd, 0x06);
	st7735_dat_write(lcd, 0x02);
	st7735_dat_write(lcd, 0x08);
	st7735_dat_write(lcd, 0x0A);
	st7735_dat_write(lcd, 0x13);
	st7735_dat_write(lcd, 0x26);
	st7735_dat_write(lcd, 0x36);
	st7735_dat_write(lcd, 0x00);
	st7735_dat_write(lcd, 0x0D);
	st7735_dat_write(lcd, 0x0E);
	st7735_dat_write(lcd, 0x10);

	st7735_cmd_write(lcd, 0x3A);
	st7735_dat_write(lcd, 0x05);

	st7735_cmd_write(lcd, 0x36);
	st7735_dat_write(lcd, 0xA8);

	st7735_cmd_write(lcd, 0x11);
	lcd->ops.time.msleep(120);
	st7735_cmd_write(lcd, 0x29);

	lcd->ops.pin.bl(HIGH);
}

void st7735_point_draw(struct st7735* lcd, uint8_t x, uint8_t y, uint16_t color)
{
	st7735_area_set(lcd, x, y, x, y);
	st7735_dat_write(lcd, color >> 8);
	st7735_dat_write(lcd, color);
}

void st7735_rect_fill(struct st7735* lcd, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint16_t* color)
{
	uint16_t i, j;
	uint16_t data;

	st7735_area_set(lcd, x1, y1, x2, y2);
	for (i = y1; i <= y2; i++) {
		for (j = x1; j <= x2; j++) {
			data = *color;
			st7735_dat_write(lcd, data >> 8);
			st7735_dat_write(lcd, data);
			color++;
		}
	}
}

void st7735_screen_fill(struct st7735* lcd, uint16_t* color)
{
	uint16_t i, j;
	uint16_t data;

	st7735_area_set(lcd, 0, 0, lcd->cfg.fix.width - 1, lcd->cfg.fix.height - 1);
	for (i = 0; i < lcd->cfg.fix.height; i++) {
		for (j = 0; j < lcd->cfg.fix.width; j++) {
			data = *color;
			st7735_dat_write(lcd, data >> 8);
			st7735_dat_write(lcd, data);
			color++;
		}
	}
}

void st7735_screen_test(struct st7735* lcd, uint16_t color)
{
	uint16_t i, j;

	st7735_area_set(lcd, 0, 0, lcd->cfg.fix.width - 1, lcd->cfg.fix.height - 1);
	for (i = 0; i < lcd->cfg.fix.height; i++) {
		for (j = 0; j < lcd->cfg.fix.width; j++) {
			st7735_dat_write(lcd, color >> 8);
			st7735_dat_write(lcd, color);
		}
	}
}

void st7735_cmd_write(struct st7735* lcd, uint8_t cmd)
{
	lcd->ops.pin.dc(LOW);
	lcd->ops.spi.write(&cmd, 1);
}

void st7735_dat_write(struct st7735* lcd, uint8_t dat)
{
	lcd->ops.pin.dc(HIGH);
	lcd->ops.spi.write(&dat, 1);
}

void st7735_area_set(struct st7735* lcd, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
{
	st7735_cmd_write(lcd, 0x2a);
	st7735_dat_write(lcd, 0x00);
	st7735_dat_write(lcd, x1);
	st7735_dat_write(lcd, 0x00);
	st7735_dat_write(lcd, x2);

	st7735_cmd_write(lcd, 0x2b);
	st7735_dat_write(lcd, 0x00);
	st7735_dat_write(lcd, y1);
	st7735_dat_write(lcd, 0x00);
	st7735_dat_write(lcd, y2);

	st7735_cmd_write(lcd, 0x2c);
}

#ifdef __cplusplus
}
#endif
